package org.kernely.directory.userpage;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.TreeSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.kernely.directory.DirectoryBundle;
import org.kernely.security.dao.UserDetailsDAO;
import org.kernely.security.persistence.UserDetails;
import org.kernely.ui.mvp.KernelyEvent;
import org.kernely.ui.mvp.KernelyEventReceiver;
import org.kernely.ui.mvp.KernelyPresenter;
import org.kernely.ui.utils.DisplayProfileEvent;

import com.vaadin.data.Property;
import com.vaadin.data.Property.ValueChangeEvent;
import com.vaadin.event.FieldEvents.TextChangeEvent;
import com.vaadin.event.FieldEvents.TextChangeListener;
import com.vaadin.event.LayoutEvents.LayoutClickEvent;
import com.vaadin.event.LayoutEvents.LayoutClickListener;
import com.vaadin.terminal.FileResource;
import com.vaadin.terminal.Sizeable;
import com.vaadin.terminal.ThemeResource;
import com.vaadin.ui.Embedded;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.Label;
import com.vaadin.ui.themes.Reindeer;

/**
 * Presenter of KernelyDirectoryView.
 */
public class KernelyDirectoryPresenter extends KernelyPresenter<KernelyDirectoryView> implements KernelyEventReceiver{

	private static final long serialVersionUID = -5295167662122849176L;
	private File file;

	/**
	 * @see org.kernely.ui.service.IKernelyPresenter#bind()
	 */
	@Override
	public final void bind() {
		// Registering as an event receiver to be called by KernelyProfileAttachedEvent
		DirectoryBundle.getEventBus().addListener(this);

		this.view.getSearchField().addListener(new TextChangeListener() {
			/**
			 * @see com.vaadin.event.FieldEvents.TextChangeListener#textChange(com.vaadin.event.FieldEvents.TextChangeEvent)
			 */
			public void textChange(TextChangeEvent event) {
				if(event.getText().length() != 0){
					if(event.getText().length() > 2){
						fillDirectory(event.getText());
					}
				}
				else{
					fillDirectory(null);
				}
			}
		});

		this.view.getSearchField().addListener(new Property.ValueChangeListener() {
			/**
			 * @see com.vaadin.data.Property.ValueChangeListener#valueChange(com.vaadin.data.Property.ValueChangeEvent)
			 */
			public void valueChange(ValueChangeEvent event) {
				if(view.getSearchField().getValue().toString().length() == 0){
					fillDirectory(null);
				}
			}
		});

	}

	/**
	 * @see org.kernely.ui.mvp.KernelyEventReceiver#handleKernelyEvent(KernelyEvent)
	 */
	public final void handleKernelyEvent(KernelyEvent event) {
		if (event instanceof KernelyDirectoryAttachedEvent){
			fillDirectory(null);
		}
	}

	/**
	 * Display the directory, eventually with search filter.
	 * Not in the constructor, because images should displayed
	 * only when the view is addedinto the application.
	 * @param search A filter on the names and firstnames.
	 */
	@SuppressWarnings("serial")
	final private void fillDirectory(String search){
		// Clear the list
		this.view.getUsersLayout().removeAllComponents();

		TreeSet<UserDetails> details = new TreeSet<UserDetails>(new NameComparator());

		// No filter
		if (search == null){
			details.addAll(UserDetailsDAO.getInstance().getAllUserDetails());
		} else {
			// Filter
			details.addAll(UserDetailsDAO.getInstance().getSearchUserDetails(search));
		}

		if (details.size() <= 0){
			// Display the last layout letter
			this.view.getUsersLayout().addComponent(new Label("No user found..."));


		} else {

			// Display the first letter
			char currentChar = Character.toUpperCase(details.first().getName().charAt(0));
			Label letterTitle = new Label(""+currentChar);
			letterTitle.setStyleName(Reindeer.LABEL_H2);
			this.view.getUsersLayout().addComponent(letterTitle);
			this.view.getUsersLayout().addComponent(new Label("<hr/>", Label.CONTENT_XHTML));

			// The layout containing the details of each letter
			HorizontalLayout usersLayout = new HorizontalLayout();
			usersLayout.setSpacing(true);

			for (final UserDetails detail : details){
				// If needed, create a new title with the char in upper case as title
				if (Character.toUpperCase(detail.getName().charAt(0)) != currentChar){

					this.view.getUsersLayout().addComponent(usersLayout);
					usersLayout = new HorizontalLayout();
					usersLayout.setSpacing(true);
					currentChar = Character.toUpperCase(detail.getName().charAt(0));
					letterTitle = new Label(""+currentChar);
					letterTitle.setStyleName(Reindeer.LABEL_H2);
					this.view.getUsersLayout().addComponent(new Label("<br/>",Label.CONTENT_XHTML));
					this.view.getUsersLayout().addComponent(letterTitle);
					this.view.getUsersLayout().addComponent(new Label("<hr/>", Label.CONTENT_XHTML));

				}

				Embedded picture = new Embedded();
				picture.setHeight(48,Sizeable.UNITS_PIXELS);
				picture.setWidth(48,Sizeable.UNITS_PIXELS);

				// Get the picture
				if (detail.getImage() == null || detail.getImage().equals("")){

					//The default image is located in src/main/resources/VAADIN/themes/kernelytheme/img
					if(detail.getCivility() == 0){
						ThemeResource imageResource = new ThemeResource("img/default_male.png");
						picture.setSource(imageResource);
					}
					else{
						ThemeResource imageResource = new ThemeResource("img/default_female.png");
						picture.setSource(imageResource);
					}
				} else {
					this.file = new File("/tmp/uploads/"+detail.getImage());
					final FileResource imageResource = new FileResource(this.file, this.view.getApplication());
					picture.setSource(imageResource);
				}

				HorizontalLayout userLayout = new HorizontalLayout();
				userLayout.setSpacing(true);

				userLayout.addListener(new LayoutClickListener() {

					/**
					 * @see com.vaadin.event.LayoutEvents.LayoutClickListener#layoutClick(com.vaadin.event.LayoutEvents.LayoutClickEvent)
					 */
					public void layoutClick(LayoutClickEvent event) {
						displayProfile(detail);
					}
				});

				String identity = null;
				String mail = null;
				String activity = (detail.getActivity() == null) ? "" : detail.getActivity()+"<br/>";
				
				// Values when no search is specified
				if (search == null){
					identity = detail.getFirstname() +" "+ detail.getName();
					mail = detail.getMail();
				// Values when a search string is specified
				} else {
					// The text is modified to highlight some parts
					// Creation of the regex
					String regexp = "(" + search + ")";
					Pattern pattern = Pattern.compile(regexp, Pattern.CASE_INSENSITIVE);

					// Search on firstname
					Matcher matcher = pattern.matcher(detail.getFirstname());
					StringBuffer buffer = new StringBuffer();
					while (matcher.find()) {
						matcher.appendReplacement(buffer, "<span style=\"background-color:#9DE8F7;\">" + matcher.group(1) + "</span>");
					}
					matcher.appendTail(buffer);
					identity = buffer.toString()+" ";

					// Search on name
					matcher = pattern.matcher(detail.getName());
					buffer = new StringBuffer();
					while (matcher.find()) {
						matcher.appendReplacement(buffer, "<span style=\"background-color:#9DE8F7;\">" + matcher.group(1) + "</span>");
					}
					matcher.appendTail(buffer);
					identity += buffer.toString();

					// Search on mail
					matcher = pattern.matcher(detail.getMail());
					buffer = new StringBuffer();
					while (matcher.find()) {
						matcher.appendReplacement(buffer, "<span style=\"background-color:#9DE8F7;\">" + matcher.group(1) + "</span>");
					}
					matcher.appendTail(buffer);
					mail = buffer.toString();

				}

				String text = "<span style=\"font-weight:bold;\">"
					+ identity + "</span><br/>"
					+ activity
					+ mail;

				Label userLabel = new Label(text,Label.CONTENT_XHTML);
				userLayout.addComponent(picture);
				userLayout.addComponent(userLabel);
				usersLayout.addComponent(userLayout);

			}

			// Display the last layout letter
			this.view.getUsersLayout().addComponent(usersLayout);

			
		}

	}	

	private void displayProfile(UserDetails detail){
		DirectoryBundle.getEventBus().broadcastEvent(new DisplayProfileEvent(this,detail));
	}

	/**
	 * Called when the presenter is no more visible.
	 */
	@Override
	public final void unset() {
		DirectoryBundle.getEventBus().removeListener(this);
	}
}
